home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / plan / src / yeardraw.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  13KB  |  450 lines

  1. /*
  2.  * year menu widgets.
  3.  *
  4.  *    clicked_calendar(x, y)        Press in calendar day box detected,
  5.  *                    pop up a one-day list menu
  6.  *    draw_year_calendar()        Draw day grid into the year calendar
  7.  *                    window
  8.  *    draw_year_day(day, month, year)    Draw one day box into the day grid
  9.  *                    in the year calendar window
  10.  *    draw_year_day_notes(day, month, year, ifyes)
  11.  *                    Draw just the notes under the day
  12.  *                    number into a day box. If ifyes is
  13.  *                    FALSE, only draw but never undraw
  14.  */
  15.  
  16. #include <time.h>
  17. #include <Xm/Xm.h>
  18. #include "cal.h"
  19.  
  20. extern char *mktimestring();
  21. extern char *parse_holidays();
  22. extern time_t date_to_time();
  23. extern struct tm *time_to_tm();
  24. extern time_t get_time();
  25. extern BOOL lookup_entry(), lookup_next_entry();
  26. static draw_year_month();
  27. static set_year_day_bkg_color();
  28. static day_to_yearpos();
  29. static yearpos_to_day_month();
  30.  
  31. static int        qx,qy,qxs,qys;    /* pos and size of quit button */
  32.  
  33. extern Display        *display;    /* everybody uses the same server */
  34. extern GC        gc;        /* everybody uses this context */
  35. extern XFontStruct    *font[NFONTS];    /* fonts: FONT_* */
  36. extern Pixmap        pixmap[NPICS];    /* common symbols */
  37. extern Widget        mainwindow;    /* raise month shell if clicked */
  38. extern struct mainmenu    mainmenu;    /* all important main window widgets */
  39. extern struct config    config;        /* global configuration data */
  40. extern int        curr_month;    /* month being displayed, 0..11 */
  41. extern int        curr_year;    /* year being displayed in cal menu */
  42. extern time_t        curr_week;    /* week being displayed, time in sec */
  43. extern struct list    *mainlist;    /* list of all schedule entries */
  44. extern struct holiday    holiday[366];    /* info for each day, separate for */
  45. extern struct holiday    sm_holiday[366];/* full-line texts under, and small */
  46. extern short        monthbegin[12];    /* julian date each month begins with*/
  47.  
  48.                     /* most recent popup made for: (only */
  49.                     /* used to keep track of yellow box) */
  50. extern int        edit_month;    /*  month being edited, 0..11 */
  51. extern int        edit_year;    /*  year being edited, since 1900 */
  52. extern int        edit_day;    /*  day being edited, 1..31 or 0 */
  53.  
  54. extern char *weekday_name[];
  55. extern char *monthname[];
  56. extern short monthlen[];
  57.  
  58.  
  59. /*
  60.  * got a click in the calendar area. If it's in a grid box with a valid
  61.  * day init, "edit" it by storing its day number in the edit_* variables.
  62.  * The previously edited day, and the new edited day are redrawn to move
  63.  * the yellow highlight.
  64.  * Also, create a day popup menu.
  65.  */
  66.  
  67. clicked_year_calendar(x, y)
  68.     int            x, y;        /* pixel pos clicked */
  69. {
  70.     int            day, month;
  71.     BOOL            *callweek;    /* if TRUE, pop up week view */
  72.     time_t            time;        /* time of day box, in sec */
  73.  
  74.     if (x >= qx && y > qy && x < qx+qxs && y < qy+qys) {
  75.         destroy_year_menu();
  76.         return;
  77.     }
  78.     if (!yearpos_to_day_month(&day, &month, &callweek, x, y) ||
  79.                     !callweek && day && day == edit_day)
  80.         return;
  81.     if (callweek) {                    /* call week view? */
  82.         struct tm tm;
  83.         tm.tm_year = curr_year;
  84.         tm.tm_mon  = month;
  85.         tm.tm_mday = day;
  86.         tm.tm_hour = 0;
  87.         tm.tm_min  = 0;
  88.         tm.tm_sec  = 0;
  89.         curr_week = tm_to_time(&tm);
  90.         create_week_menu();
  91.         return;
  92.     }
  93.     if (day == 0) {                    /* call month view? */
  94.         curr_month = month;
  95.         draw_month_year();
  96.         draw_calendar();
  97.         XRaiseWindow(display, XtWindow(mainwindow));
  98.         return;
  99.     }
  100.     if (edit_day) {                    /* call day menu */
  101.         int oldday = edit_day;
  102.         edit_day = 0;
  103.         draw_day(oldday);
  104.         draw_year_day(oldday, edit_month, edit_year);
  105.         draw_week_day(oldday, edit_month, edit_year);
  106.     }
  107.     edit_day   = day;
  108.     edit_month = month;
  109.     edit_year  = curr_year;
  110.     draw_day(edit_day);
  111.     draw_year_day(edit_day, edit_month, edit_year);
  112.     draw_week_day(edit_day, edit_month, edit_year);
  113.     if (time = date_to_time(day, month, curr_year, 0, 0, 0))
  114.         create_list_popup(mainlist, time,
  115.                 (time_t)0, (char *)0, (struct entry *)0);
  116. }
  117.  
  118.  
  119. /*-------------------------------------------------- drawing ----------------*/
  120. /*
  121.  * draw the entire year menu
  122.  */
  123.  
  124. draw_year_calendar()
  125. {
  126.     register struct config    *c = &config;
  127.     Window            window;
  128.     char            buf[20];
  129.     int            month;
  130.     int            i;
  131.  
  132.     if (!mainmenu.yearcal)
  133.         return;
  134.     window = XtWindow(mainmenu.yearcal);
  135.     set_color(COL_YBACK);
  136.     XFillRectangle(display, window, gc, 0, 0, 9999, 9999);
  137.  
  138.     set_color(COL_YGRID);                /* quit button */
  139.     qx  = qy = 10;
  140.     qxs = 10 + strlen_in_pixels("Done", FONT_STD);
  141.     qys =  4 + font[FONT_STD]->max_bounds.ascent;
  142.     XDrawRectangle(display, window, gc, qx, qy, qxs, qys);
  143.     XSetFont(display, gc, font[FONT_STD]->fid);
  144.     XDrawString(display, window, gc,
  145.         qx+5, qy+font[FONT_STD]->max_bounds.ascent, "Done", 4);
  146.  
  147.     sprintf(buf, "%d", 1900 + curr_year);        /* year number */
  148.     set_color(COL_YTITLE);
  149.     XSetFont(display, gc, font[FONT_YTITLE]->fid);
  150.     i = 4 * font[FONT_YTITLE]->per_char
  151.             ['0' - font[FONT_YTITLE]->min_char_or_byte2].width;
  152.     XDrawString(display, window, gc,
  153.         c->year_margin + (c->yearbox_xs*7*4 + c->year_gap*3 - i)/2,
  154.         c->year_margin + c->year_title * 3/4,
  155.         buf, strlen(buf));
  156.  
  157.     for (month=0; month < 12; month++)        /* months */
  158.         draw_year_month(month, curr_year,
  159.             c->year_margin +
  160.                 month%4 * (c->yearbox_xs*7 + c->year_gap),
  161.             c->year_margin + c->year_title + c->year_gap +
  162.                 month/4 * (c->yearbox_ys*8 + c->year_gap));
  163.     set_color(COL_STD);
  164. }
  165.  
  166.  
  167. /*
  168.  * draw entire month at the specified position
  169.  */
  170.  
  171. static draw_year_month(month, year, x, y)
  172.     int            month, year;
  173.     int            x, y;
  174. {
  175.     register struct config    *c = &config;
  176.     Window            window = XtWindow(mainmenu.yearcal);
  177.     XPoint            point[4];
  178.     int            i, j;
  179.  
  180.                             /* days */
  181.     for (i=1; i < 32; i++)
  182.         draw_year_daybox(i, month, year, x, y+2*c->yearbox_ys);
  183.  
  184.                             /* month name */
  185.     set_color(COL_YMONTH);
  186.     XSetFont(display, gc, font[FONT_YMONTH]->fid);
  187.     XDrawString(display, window, gc,
  188.             x, y + c->yearbox_ys * 3/4,
  189.             monthname[month], strlen(monthname[month]));
  190.  
  191.                             /* weekday names */
  192.     j = c->sunday_first ? 6 : 0;
  193.     set_color(COL_YWEEKDAY);
  194.     XSetFont(display, gc, font[FONT_YDAY]->fid);
  195.     for (i=0; i < 7; i++, j++)
  196.         XDrawString(display, window, gc,
  197.                 x + i * c->yearbox_xs, y + c->yearbox_ys * 7/4,
  198.                 weekday_name[j%7], strlen(weekday_name[j%7]));
  199.  
  200.                             /* month box */
  201.     set_color(COL_YGRID);
  202.     XDrawRectangle(display, window, gc, x-1, y-1 + 2*c->yearbox_ys,
  203.                     7*c->yearbox_xs+1, 6*c->yearbox_ys+1);
  204.  
  205.     point[3].x =                    /* week call arrows */
  206.     point[0].x =
  207.     point[1].x = x-8;
  208.     point[2].x = x-4;
  209.     point[2].y = y-1 + c->yearbox_ys * 5/2;
  210.     point[3].y =
  211.     point[0].y = point[2].y - (point[2].x - point[0].x);
  212.     point[1].y = point[2].y + (point[2].x - point[0].x);
  213.     if (c->calbox_arrow[0] > 3)
  214.         for (i=0; i < 6; i++) {
  215.             set_color(COL_YBOXBACK);
  216.             XFillPolygon(display, window, gc, point, 3, Convex,
  217.                             CoordModeOrigin);
  218.             set_color(COL_YGRID);
  219.             XDrawLines(display, window, gc, point, 4,
  220.                             CoordModeOrigin);
  221.             point[0].y += c->yearbox_ys;
  222.             point[1].y += c->yearbox_ys;
  223.             point[2].y += c->yearbox_ys;
  224.             point[3].y += c->yearbox_ys;
  225.         }
  226.     set_color(COL_STD);
  227. }
  228.  
  229.  
  230. /*
  231.  * draw one day box. The first routine is an interface for outside routines;
  232.  * to turn the next day green at midnight etc. The second routine is for
  233.  * internal use; it requires a X/Y coordinate.
  234.  */
  235.  
  236. draw_year_day(day, month, year)
  237.     int            day;        /* 1..31 */
  238.     int            month;        /* 0..11 */
  239.     int            year;        /* year since 1900 */
  240. {
  241.     register struct config    *c = &config;
  242.  
  243.     if (!mainmenu.yearcal || year != curr_year)
  244.         return;
  245.     draw_year_daybox(day, month, year,
  246.             c->year_margin +
  247.                 month%4 * (c->yearbox_xs*7 + c->year_gap),
  248.             c->year_margin + c->year_title + c->year_gap +
  249.                 month/4 * (c->yearbox_ys*8 + c->year_gap)+
  250.                 2*c->yearbox_ys);
  251. }
  252.  
  253. draw_year_daybox(day, month, year, x, y)
  254.     int            day;        /* 1..31 */
  255.     int            month, year;
  256.     int            x, y;        /* upper right of first day */
  257. {
  258.     Window            window = XtWindow(mainmenu.yearcal);
  259.     int            dx, dy;        /* position in calendar */
  260.     char            buf[20];
  261.     BOOL            weekend;    /* saturday or sunday? */
  262.     int            jul;        /* julian date of daybox */
  263.     struct holiday        *hp, *shp;    /* holiday info for this day */
  264.     char            *errmsg;    /* holiday parser error */
  265.  
  266.     if (errmsg = parse_holidays(year, FALSE))
  267.         create_error_popup(mainmenu.cal, 0, errmsg);
  268.     jul = monthbegin[month] + day-1 + (month>1 && !(year&3));
  269.     hp  = &holiday[jul];
  270.     shp = &sm_holiday[jul];
  271.  
  272.     if (!day_to_yearpos(&dx, &dy, day, month, year))
  273.         return;
  274.     weekend = dx == 6 || dx == (config.sunday_first ? 0 : 5);
  275.     x += dx * config.yearbox_xs;
  276.     y += dy * config.yearbox_ys;
  277.  
  278.     set_year_day_bkg_color(day, month, year);
  279.     XFillRectangle(display, window, gc, x+1, y+1, config.yearbox_xs-2,
  280.                               config.yearbox_ys-2);
  281.     sprintf(buf, "%d", day);
  282.     XSetFont(display, gc, font[FONT_YNUM]->fid);
  283.     set_color( hp->daycolor    ?  hp->daycolor :
  284.           shp->daycolor ? shp->daycolor :
  285.           weekend    ? COL_WEEKEND    : COL_WEEKDAY);
  286.     XDrawString(display, window, gc,
  287.         x+2, y+font[FONT_YNUM]->max_bounds.ascent, buf, strlen(buf));
  288.  
  289.     draw_year_day_notes(day, month, year, TRUE);
  290. }
  291.  
  292.  
  293. /*
  294.  * draw (or undraw) the notes in a day box. Looks up the day in the database.
  295.  * This is very inefficient, it should cache the previously found entry. At
  296.  * the moment, it's O(n^2).
  297.  */
  298.  
  299. draw_year_day_notes(day, month, year, ifyes)
  300.     int            day;        /* 1..31 */
  301.     int            month;        /* 0..11 */
  302.     int            year;        /* year since 1900 */
  303.     BOOL            ifyes;        /* only draw, never undraw */
  304. {
  305.     register struct config    *c = &config;
  306.     struct lookup        lookup;        /* result of entry lookup */
  307.     time_t            time;        /* time of day box, in sec */
  308.     int            x, y;        /* position in calendar */
  309.     register struct entry    *ep;        /* ptr to entry in mainlist */
  310.     BOOL            found;        /* TRUE if lookup succeeded */
  311.  
  312.     if (!mainmenu.yearcal || year != curr_year)
  313.         return;
  314.     if (!day_to_yearpos(&x, &y, day, month, year) ||
  315.         !(time = date_to_time(day, month, year, 0, 0, 0)))
  316.         return;
  317.  
  318.     x  = c->year_margin +    month%4 * (c->yearbox_xs*7 + c->year_gap) +
  319.                 c->yearbox_xs - 8 - 2 +
  320.                 x * c->yearbox_xs;
  321.     y  = c->year_margin + c->year_title + c->year_gap +
  322.                 month/4 * (c->yearbox_ys*8 + c->year_gap) +
  323.                 3*c->yearbox_ys -10 +
  324.                 y * c->yearbox_ys;
  325.  
  326.     found = lookup_entry(&lookup, mainlist, time, TRUE, FALSE);
  327.     for (; found; found = lookup_next_entry(&lookup)) {
  328.         ep = &mainlist->entry[lookup.index];
  329.         if (ep->note && (*ep->note == '-' || *ep->note == '='))
  330.             continue;
  331.         if (lookup.index   <  mainlist->nentries &&
  332.             lookup.trigger >= time         &&
  333.             lookup.trigger <  time + 86400)
  334.             break;
  335.     }
  336.     if (found)
  337.         set_color(COL_YNUMBER);
  338.     else
  339.         if (ifyes)
  340.             set_year_day_bkg_color(day, month, year);
  341.         else
  342.             return;
  343.  
  344.     XFillRectangle(display, XtWindow(mainmenu.yearcal), gc, x, y, 3, 3);
  345.     set_color(COL_STD);
  346. }
  347.  
  348.  
  349. static set_year_day_bkg_color(day, month, year)
  350.     int            day;        /* 1..31 */
  351.     int            month, year;
  352. {
  353.     struct tm        *tm;
  354.  
  355.     tm = time_to_tm(get_time());
  356.     if    (day   == edit_day    &&
  357.          year  == edit_year   &&
  358.          month == edit_month)
  359.                         set_color(COL_CALACT);
  360.  
  361.     else if    (day   == tm->tm_mday &&
  362.          month == tm->tm_mon  &&
  363.          year  == tm->tm_year)
  364.                         set_color(COL_CALTODAY);
  365.     else
  366.                         set_color(COL_YBOXBACK);
  367. }
  368.  
  369.  
  370. /*-------------------------------------------------- low-level --------------*/
  371. static day_to_yearpos(x, y, day, month, year)
  372.     int            *x, *y;        /* returned box, 0..6/0..5 */
  373.     int            day;        /* 1..31 */
  374.     int            month, year;
  375. {
  376.     int            wkday;
  377.  
  378.     if (!date_to_time(day, month, year, &wkday, 0, 0))
  379.         return(FALSE);
  380.     *x = config.sunday_first ?  wkday : (wkday + 6) % 7;
  381.     *y = (day-1 - *x + 6) / 7;
  382.     return(TRUE);
  383. }
  384.  
  385.  
  386. /*
  387.  * check where on the year calendar the user pressed, and return the month
  388.  * and day. If the returned day is 0, the user clicked on the month name.
  389.  * If the user clicked on one of the week call arrows to the left of each
  390.  * week row, set *callweek and return the first day of that week.
  391.  */
  392.  
  393. static yearpos_to_day_month(day, month, callweek, x, y)
  394.     int            *day;        /* returned day #, 1..31 or 0*/
  395.     int            *month;        /* returned month #, 0..11 */
  396.     BOOL            *callweek;    /* if TRUE, pop up week view */
  397.     int            x, y;        /* pixel pos in drawable */
  398. {
  399.     register struct config    *c = &config;
  400.     int            dx, dy;        /* month box size, with gap */
  401.     int            xtest, ytest;    /* temps */
  402.  
  403.     *callweek = FALSE;
  404.     dx = c->year_gap + 7*c->yearbox_xs;
  405.     x -= c->year_margin - c->year_gap;
  406.     xtest = x / dx;
  407.     x -= xtest * dx;
  408.  
  409.     dy = c->year_gap + 8*c->yearbox_ys;
  410.     y -= c->year_margin + c->year_title + c->year_gap - c->yearbox_ys;
  411.     ytest = y / dy;
  412.     y -= ytest * dy;
  413.  
  414.     if (xtest < 0 || xtest > 3 || ytest < 0 || ytest > 2)
  415.         return(FALSE);
  416.     *month = 4*ytest + xtest;
  417.  
  418.     if (x < c->year_gap) {
  419.         y = y / c->yearbox_ys -3;
  420.         if (y < 0 || y > 5)
  421.             return(FALSE);
  422.         (void)day_to_yearpos(&xtest, &ytest, 1, *month, curr_year);
  423.         *day = 7 * y - xtest +1;
  424.         if (*day < 1) {
  425.             if (--*month < 0)
  426.                 return(FALSE);
  427.             *day += monthlen[*month] +
  428.                     (*month==1 && !(curr_year&3));
  429.         }
  430.         *callweek = TRUE;
  431.         return(*day <= monthlen[*month]);
  432.     }
  433.  
  434.     (void)day_to_yearpos(&xtest, &ytest, 1, *month, curr_year);
  435.     if (x < 0 || y < 0)
  436.         return(FALSE);
  437.     x -= c->year_gap;
  438.     x /= c->yearbox_xs;
  439.     y /= c->yearbox_ys;
  440.     if (y < 0)
  441.         return(FALSE);
  442.     if (y < 3) {
  443.         *day = 0;
  444.         return(TRUE);
  445.     }
  446.     *day = (y-3) * 7 + x - xtest + 1;
  447.     return(*day > 0 &&
  448.            day_to_yearpos(&xtest, &ytest, *day, *month, curr_year));
  449. }
  450.